using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.Networking;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.U2D;


namespace SLAssetSystem
{
    public class AssetSystem:Singleton<AssetSystem>,IInitable
    {
        public StringBuilder loger = new StringBuilder();

        public override void Init()
        {
            base.Init();
        }
        public IList<IResourceLocation> GetLocationByLabel(string label)
        {
            var ResourceLocators = Addressables.ResourceLocators;
            IList<IResourceLocation> locations = null;
            HashSet<IResourceLocation> current = null;
            foreach (var locator in ResourceLocators)//没有自己添加的话一般就一个
            {
                locator.Locate(label, typeof(object), out var locs);
                if (locations == null)
                {
                    //simple, common case, no allocations
                    locations = locs;
                }
                else
                {
                    //less common, need to merge...
                    if (current == null)
                    {
                        current = new HashSet<IResourceLocation>();
                        foreach (var loc in locations)
                            current.Add(loc);
                    }
                    if (locs != null)
                    {
                        current.UnionWith(locs);
                    }
                }
            }
            if (current == null)
                return locations;

            return new List<IResourceLocation>(current); ;
        }

        #region 检测更新
        public AsyncOperationHandle<List<string>> CheckForCatalogUpdates()
        {
            return Addressables.CheckForCatalogUpdates(false);
        }

        public AsyncOperationHandle<List<IResourceLocator>> UpdateCatalogs( IEnumerable<string> catalogs = null, bool autoReleaseHandle = true)
        {
            return Addressables.UpdateCatalogs(catalogs, autoReleaseHandle);
        }

        #endregion

        #region 加载资源
        /// <summary>
        ///  异步加载资源
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="_path">地址或者Label/param>
        /// <param name="_loaded">回调</param>
        public AsyncOperationHandle<T> LoadAssetAsync<T>(string path, Action<T> _loaded = null)
        {
            loger.AppendLine(path);

            var handle = Addressables.LoadAssetAsync<T>(path);
            handle.Completed += (p) =>
            {
                if (p.Status == AsyncOperationStatus.Succeeded)
                    _loaded?.Invoke(p.Result);
                else
                    throw new Exception("load fail: " + path);
            };
            return handle;
        }


        /// <summary>
        /// GameObject在加载后清理掉句柄，否则会出现
        /// 非GameObject回不需要清理引用，卸载资源即可
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="path"></param>
        /// <param name="isAutoRelease"></param>
        /// <returns></returns>
        public T LoadAssetSync<T>(string path, bool isAutoRelease = false)
        {
            loger.AppendLine(path);

            var op = Addressables.LoadAssetAsync<T>(path);
            T assset = op.WaitForCompletion();
            if (isAutoRelease)
            {
                Release(op);
            }
            return assset;
        }

        public AsyncOperationHandle<IList<TObject>> LoadAssetsAsync<TObject>(string path, Action<IList<TObject>> _loaded)
        {
            loger.AppendLine(path);

            var handle = Addressables.LoadAssetsAsync<TObject>(path, null);
            handle.Completed += (p) =>
            {
                if (p.Status == AsyncOperationStatus.Succeeded)
                    _loaded?.Invoke(p.Result);
                else
                    throw new Exception("load fail: " + path);
            };
            return handle;
        }

        public IList<TObject> LoadAssetsSync<TObject>(string path)
        {
            loger.AppendLine(path);

            var handle = Addressables.LoadAssetsAsync<TObject>(path, null);
            var result = handle.WaitForCompletion();
            return result;
        }

        #endregion

        #region 实例化

        /// <summary>
        /// Async Instance
        /// </summary>
        /// <param name="_path">地址或者Label</param>
        /// <param name="_loaded">回调</param>
        /// <param name="parent">Parent</param>
        /// <param name="是否生成在世界空间">instantiateInWorldSpace</param>
        /// <param name="trackHandle">跟踪节点</param>
        public AsyncOperationHandle<GameObject> InstantiateAsync(string path, Action<GameObject> _loaded = null, Transform parent = null, bool instantiateInWorldSpace = false, bool trackHandle = true)
        {
            loger.AppendLine(path);

            var handle = Addressables.InstantiateAsync(path, parent, instantiateInWorldSpace, trackHandle);
            handle.Completed += (p) =>
            {
                _loaded?.Invoke(p.Result);
            };
            return handle;
        }

        public void InstantiatesAsync(string name, int count, Transform parent, Action<GameObject[]> onLoaded)
        {
            GameObject[] gameObjects = new GameObject[count];
            for (int i = 0; i < count; i++)
            {
                gameObjects[i] = InstantiateSync(name, parent);
            }
            onLoaded?.Invoke(gameObjects);
        }

        public GameObject InstantiateSync(string path, Transform root = null)
        {
            loger.AppendLine(path);

            var op = Addressables.InstantiateAsync(path, root);
            GameObject go = op.WaitForCompletion();
            return go;
        }

        #endregion

        #region  根据图集加载图片
        /// <summary>
        /// AsyncLoadSpriteByAltas
        /// </summary>
        /// <param name="path">地址或者Label</param>
        /// <param name="spriteName">图片名</param>
        /// <param name="_loaded">回调</param>
        public void LoadAsyncSpriteByAltas(string path, string spriteName, Action<Sprite> _loaded = null)
        {
            var op = Addressables.LoadAssetAsync<SpriteAtlas>(path);
            op.Completed += (p) =>
            {
                if (p.Status == AsyncOperationStatus.Succeeded)
                    _loaded?.Invoke(p.Result.GetSprite(spriteName));
                else
                    throw new Exception("load fail: " + path);
            };
        }
        #endregion

        //#region 根据Label加载所有资源
        ///// <summary>
        ///// 根据Label加载所有资源
        ///// </summary>
        ///// <typeparam name="T">类型</typeparam>
        ///// <param name="label">Label</param>
        ///// <param name="_oneLoaded">加载完一个回调，但是并不知道是哪一个</param>
        ///// <param name="completeCallBack">所有加载完回调</param>
        //public void LoadAssetsAsyncByLabel<T>(string label, Action<T> _oneLoaded = null, Action<IList<T>> completeCallBack = null)
        //{
        //    var op = Addressables.LoadAssetsAsync<T>(label, p =>
        //    {
        //        _oneLoaded?.Invoke(p);
        //    });

        //    op.Completed += p =>
        //    {
        //        if (p.Status == AsyncOperationStatus.Succeeded)
        //            completeCallBack?.Invoke(p.Result);
        //        else
        //            throw new Exception("load label: " + label);
        //    };
        //}
        //#endregion

        //#region 根据Label和Path进行组合标签加载
        ///// <summary>
        ///// 根据Label和Path进行组合标签加载
        ///// </summary>
        ///// <typeparam name="T">类型</typeparam>
        ///// <param name="keys">Label和Path组成的list</param>
        ///// <param name="mergeMode">MergeMode 1、默认选择第一个内容进行删选 2、并集 3、交集</param>
        ///// <param name="_oneLoaded">加载完一个回调，但是并不知道是哪一个</param>
        ///// <param name="completeCallBack">所有加载完回调</param>
        //public void LoadAssetsAsyncByLabelOrName<T>(IEnumerable keys, Addressables.MergeMode mergeMode = Addressables.MergeMode.Intersection, Action<T> _oneLoaded = null, Action<IList<T>> completeCallBack = null)
        //{
        //    Addressables.LoadAssetsAsync<T>(keys, p =>
        //    {
        //        _oneLoaded?.Invoke(p);
        //    }, mergeMode).Completed += p =>
        //    {
        //        if (p.Status == AsyncOperationStatus.Succeeded)
        //            completeCallBack?.Invoke(p.Result);
        //        else
        //            throw new Exception("load fail: " + keys);
        //    };

        //}
        //#endregion


        #region 卸载资源
        /// <summary>
        /// 卸载资源
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="source">资源</param>
        public void ReleaseAsset<T>(T source)
        {
            Addressables.Release<T>(source);
        }

        public void Release<T>(AsyncOperationHandle<T> handle)
        {
            Addressables.Release<T>(handle);
        }

        public void Release(AsyncOperationHandle handle)
        {
            Addressables.Release(handle);
        }

        public void ReleaseInstance(GameObject obj)
        {
            if (!Addressables.ReleaseInstance(obj))
            {
                MonoBehaviour.Destroy(obj);
            }
        }

        public bool ReleaseInstance(AsyncOperationHandle handle)
        {
            return Addressables.ReleaseInstance(handle);
        }

        public bool ReleaseInstance(AsyncOperationHandle<GameObject> handle)
        {
            return Addressables.ReleaseInstance(handle);
        }
        #endregion

    }
}


